Object Oriented Programming

In Object Oriented Programming, everything is an object. Objects are real world entities having some attributes and some related methods that operate on attributes. We assume that the reader has some familiarity with Object Oriented Concepts such as Inheritance, Polymorphism, Abstraction and so on ...

Defining Classes

Syntax:

class ClassName:
        <statement 1>
        <statement 2>
        ....
        ....
        <statement n>

Special Methods inside the class

Unlike C++ and Java classes, class methods does not hold the reference of current object (this object). Class methods should take the class object as their first argument. This is not required for static methods. At the point of invocation of object methods, the object is passed to method implicitly. It is a covention to name the first parameter of class method as self. Now let's see some special functions of classes.

  • __init__(self,elements) : Constructor, called when object is created. All properties of the object have to be declared here.

  • __del__(self) : Destructor, called when del is applied to an object.

  • __str__(self) : Returns the string representation of object. Called when str() is called on the object.

  • __iter__(self) : Returns the iterator of elements of the object. Called when iter() is called on the object. Also this enables us to use the for ele in object like construct.

  • __len(self)__ : Returns the length of the collection. Called when len() is invoked on the object.
  • __getitem(self,item)__ : Allows us to use object[item] like accessor to get an item

Static members and methods

Any member declared inside the class, but not in the methods, are shared by all instances of classes. A method annotated with @staticmethod is static method, and doesn't recieve class object as it's first parameter.

A note on private members

A member or method whose name starts with '__' is regarded as a private member or method.

A sample class, Student

Here we implement a simple Student class.


In [86]:
class Student:
    count = 0 # Total number of objects created so far, it is static variable as it is declared outside
    
    def __init__(self,name,usn,marks):
        """
        Constructor of class Student
        Input: name - name of the student : string
               usn  - university serial number : string
               marks - marks in 3 subjects out of 20
        """
        Student.count += 1
        self.name = name 
        self.usn  = usn
        self.marks = marks[:] # Copy marks to self.marks .. a simple self.marks = marks make only reference equal
    
    def print_details(self):
        print(str(self))
    
    def total_marks(self):
        return sum(self.marks)
        
    def __iter__(self):
        details = {'name':self.name,'usn':self.usn,'marks':self.marks}
        for k,v in details.items():
            yield k,v # A tuple
    
    def __str__(self):
        return "Name : {0} \nUSN = {1}\nMarks in 3 subjects = {2}".format(self.name,self.usn,self.marks)
    
    @staticmethod
    def get_total_count():
        return Student.count

In [87]:
s1 = Student('Ramesh','4jc11cs111',[20,16,18])
s2 = Student('Ravi','4jc15cs112',[15,18,18])

In [88]:
print(s1) # calls __str__()


Name : Ramesh 
USN = 4jc11cs111
Marks in 3 subjects = [20, 16, 18]

In [89]:
print(s2)


Name : Ravi 
USN = 4jc15cs112
Marks in 3 subjects = [15, 18, 18]

In [91]:
Student.count


Out[91]:
2

In [90]:
Student.get_total_count()


Out[90]:
2

In [92]:
for k,v in s1:
    print('{} = {}'.format(k,v))


usn = 4jc11cs111
name = Ramesh
marks = [20, 16, 18]

In [95]:
s1.print_details()       # self of Student.print_details(self) is passed as s1


Name : Ramesh 
USN = 4jc11cs111
Marks in 3 subjects = [20, 16, 18]

In [97]:
Student.print_details(s1) # Explicitly passing self parameter


Name : Ramesh 
USN = 4jc11cs111
Marks in 3 subjects = [20, 16, 18]

In [98]:
Student.get_total_count()


Out[98]:
2

In [100]:
s1.get_total_count()   # This is also possible, @staticmethod attribute prevents passing object to method


Out[100]:
2

Duck Typing and Interfaces

In C, C++, Java and C#, we have to predefine the data type of every variable declared. In Python, you may have observed that you are not defining any data type during variable declaration. In fact, Python does not require you to do that.

In C,

int x;

means storage space allocated to x is constant 8 bytes (on x64 system) and this space will never change. This also implies that x will never hold other values than int. Trying to do so will raise a compiler error. This nature of C makes the language statically typed, i.e., data type of a variable is determined at the compile time.

On the other hand, in Python, the type of variable is determined entirely during runtime. Storage space allocated to a variable can vary dynamically. When we assign a string to a variable x, it will be str. If we reassign it to a list, it will be list. This nature of Python makes it dynamically typed language. It is also called as Duck typing.

Duck typing is an application of the duck test in type safety. It requires that type checking be deferred to runtime, and is implemented by means of dynamic typing or reflection.

The Duck test is a humorous term for a form of abductive reasoning. This is its usual expression:

If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

The duck test can be seen in the following example. As far as the function in_the_forest is concerned, the Person object is a duck:


In [1]:
class Duck:
    def quack(self):
        print("Quaaaaaack!")
    def feathers(self):
        print("The duck has white and gray feathers.")

class Person:
    def quack(self):
        print("The person imitates a duck.")
    def feathers(self):
        print("The person takes a feather from the ground and shows it.")
    def name(self):
        print("John Smith")

def in_the_forest(duck):
    duck.quack()
    duck.feathers()

def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_forest(john)

game()


Quaaaaaack!
The duck has white and gray feathers.
The person imitates a duck.
The person takes a feather from the ground and shows it.

type() - Obtaining the data type of a variable


In [102]:
x = 8
type(x)


Out[102]:
int

In [103]:
type(8.5)


Out[103]:
float

In [104]:
type('hello')


Out[104]:
str

In [105]:
type([1,2,1])


Out[105]:
list

In [106]:
type({})


Out[106]:
dict

In [108]:
type((1,))


Out[108]:
tuple

In [109]:
type(s1)


Out[109]:
__main__.Student

In [111]:
import random
type(random)


Out[111]:
module

The main intention of interfaces in Java and C# was to make the classes to have a set of common functions, which makes their usage alike. Due to Duck Typing, the need for interfaces is now gone